package cn.jly.boot.mp.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * 为了提高兼容性和效率，本redisUtils的所有键值对均采用String类型，对象需要被序列化成json字符串
 *
 * @PackageName cn.jly.boot.mp.utils
 * @ClassName RedisUtils
 * @Author 姬岚洋
 * @Description redis工具类
 * @Date 2020/01/04 下午 3:46
 */
@Component
public class RedisUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(RedisUtils.class);

    /**
     * 默认的过期时间，七天
     */
    private static final long DEFAULT_EXPIRE_TIME = 60 * 60 * 24 * 7;

    // @Autowired
    // RedisTemplate redisTemplate;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    /**
     * 获取stringRedisTemplate
     *
     * @return
     */
    public StringRedisTemplate getStringRedisTemplate() {
        return stringRedisTemplate;
    }

    /**
     * 返回所有的key
     *
     * @param pattern
     * @return
     */
    public Set<String> keys(String pattern) {
        return stringRedisTemplate.keys(pattern);
    }

    /**
     * 简单k-v设值
     *
     * @param key
     * @param value 普通字符串或者是value的json
     * @return
     */
    public boolean set(final String key, String value) {
        return set(key, value, -1L);
    }

    /**
     * 携带过期时间的k-v设值
     *
     * @param key
     * @param value      普通字符串或者是value的json
     * @param expireTime 过期时间，单位秒
     * @return
     */
    public boolean set(final String key, String value, long expireTime) {
        boolean result = false;
        try {
            ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
            operations.set(key, value);
            // 设置过期时间
            if (expireTime >= 0L) {
                stringRedisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            }
            result = true;
        } catch (Exception e) {
            LOGGER.error("set error: key {}, value {}, expireTime {}, caused by {}", key, value, expireTime, e);
        }
        return result;
    }

    /**
     * 判断某个key是否存在
     *
     * @param key
     * @return
     */
    public boolean exists(final String key) {
        return stringRedisTemplate.hasKey(key);
    }

    /**
     * 获取指定的key对应的值
     *
     * @param key
     * @return 普通字符串或者是value的json
     */
    public String get(final String key) {
        String result;
        ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
        result = operations.get(key);
        return result;
    }

    /**
     * 删除指定的key
     *
     * @param key
     * @return
     */
    public boolean remove(final String key) {
        boolean result = false;
        try {
            if (exists(key)) {
                stringRedisTemplate.delete(key);
            }
            result = true;
        } catch (Exception e) {
            LOGGER.error("remove error: key {}, caused by {}", key, e);
        }

        return result;
    }

    /**
     * 批量删除
     *
     * @param keys
     */
    public void remove(final String... keys) {
        for (String key : keys) {
            remove(key);
        }
    }

    /**
     * 按照指定的模式批量删除
     *
     * @param pattern
     * @return
     */
    public boolean removePattern(final String pattern) {
        boolean result = false;
        try {
            Set<String> keys = stringRedisTemplate.keys(pattern);
            if (keys.size() > 0) {
                stringRedisTemplate.delete(keys);
            }
            result = true;
        } catch (Exception e) {
            LOGGER.error("removePattern error: pattern {}, caused by {}", pattern, e);
        }

        return result;
    }

    /**
     * hash set，过期时间默认是一周
     *
     * @param key
     * @param hashKey
     * @param value   普通字符串或者是value的json
     */
    public boolean hashSet(String key, String hashKey, String value) {
        return hashSetWithExpire(key, hashKey, value, DEFAULT_EXPIRE_TIME);
    }

    /**
     * 包含过期时间的hashSet
     *
     * @param key
     * @param hashKey
     * @param value      普通字符串或者是value的json
     * @param expireTime 过期时间，单位秒
     */
    public boolean hashSetWithExpire(String key, String hashKey, String value, long expireTime) {
        boolean result = false;
        try {
            HashOperations<String, String, String> hash = stringRedisTemplate.opsForHash();
            hash.put(key, hashKey, value);
            stringRedisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            LOGGER.error("hashSet error: key {}, hashKey {}, value {}, expireTime {}, caused by {}", key, hashKey, value, expireTime, e);
        }

        return result;
    }

    /**
     * hash get
     *
     * @param key
     * @param hashKey
     * @return 普通字符串或者是value的json
     */
    public String hashGet(String key, String hashKey) {
        HashOperations<String, String, String> hash = stringRedisTemplate.opsForHash();
        return hash.get(key, hashKey);
    }

    /**
     * 根据指定的key获取所有的hash value
     *
     * @param key
     * @return hash组成的map
     */
    public Map<String, String> hashGetEntry(String key) {
        final HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
        return hashOperations.entries(key);
    }

    /**
     * 入队
     *
     * @param key
     * @param value 普通字符串或者是value的json
     */
    public boolean pushList(String key, String value) {
        return pushListWithExpire(key, value, DEFAULT_EXPIRE_TIME);
    }

    /**
     * 带有过期时间的入队
     *
     * @param key
     * @param value      普通字符串或者是value的json
     * @param expireTime 过期时间
     */
    public boolean pushListWithExpire(String key, String value, long expireTime) {
        boolean result = false;
        try {
            final ListOperations<String, String> listOperations = stringRedisTemplate.opsForList();
            listOperations.leftPush(key, value);
            stringRedisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            LOGGER.error("pushList error: key {}, value {}, expireTime {}, caused by {}", key, value, expireTime, e);
        }

        return result;
    }

    /**
     * list range
     *
     * @param key
     * @param start 开始索引
     * @param end   结束索引
     * @return 普通字符串或者是value的json
     */
    public List<String> range(String key, long start, long end) {
        ListOperations<String, String> list = stringRedisTemplate.opsForList();
        return list.range(key, start, end);
    }

    /**
     * set add
     *
     * @param key
     * @param value 普通字符串或者是value的json
     */
    public boolean setAdd(String key, String value) {
        return setAddWithExpire(key, value, DEFAULT_EXPIRE_TIME);
    }

    /**
     * 带有过期时间的set add
     *
     * @param key
     * @param value      普通字符串或者是value的json
     * @param expireTime 过期时间，单位是秒
     * @return
     */
    public boolean setAddWithExpire(String key, String value, long expireTime) {
        boolean result = false;
        try {
            SetOperations<String, String> set = stringRedisTemplate.opsForSet();
            set.add(key, value);
            result = true;
        } catch (Exception e) {
            LOGGER.error("setAdd error: key {}, value {}, expireTime {}, caused by {}", key, value, expireTime, e);
        }

        return result;
    }

    /**
     * set get
     *
     * @param key
     * @return 普通字符串的集合或者是value的json的集合
     */
    public Set<String> setMembers(String key) {
        SetOperations<String, String> set = stringRedisTemplate.opsForSet();
        return set.members(key);
    }

    /**
     * zadd
     *
     * @param key
     * @param value 普通字符串或者是value的json
     * @param score
     * @return
     */
    public boolean zAdd(String key, String value, double score) {
        return zAddWithExpire(key, value, score, DEFAULT_EXPIRE_TIME);
    }

    /**
     * 带有过期时间的ordered set add
     *
     * @param key
     * @param value 普通字符串或者是value的json
     * @param score
     */
    public boolean zAddWithExpire(String key, String value, double score, long expireTime) {
        boolean result = false;
        try {
            ZSetOperations<String, String> zset = stringRedisTemplate.opsForZSet();
            zset.add(key, value, score);
            stringRedisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            LOGGER.error("zAdd error: key {}, value {}, score {}, expireTime {}, caused by {}", key, value, score, expireTime, e);
        }

        return result;
    }

    /**
     * rangeByScore
     *
     * @param key
     * @param minScore
     * @param maxScore
     * @return 普通字符串集合或者是value的json集合
     */
    public Set<String> rangeByScore(String key, double minScore, double maxScore) {
        ZSetOperations<String, String> zset = stringRedisTemplate.opsForZSet();
        return zset.rangeByScore(key, minScore, maxScore);
    }
}
